#ifndef _MYTHREADPOOL_H_
#define _MYTHREADPOOL_H_

#include <stdio.h>  
#include <stdlib.h>  
#include <assert.h>   
#include <memory>   
#include <thread>   
#include <queue>   
#include <mutex>
#include <functional>
#include <condition_variable>

// linux
#include <unistd.h>  
#include <sys/types.h>  

#include "config.h"

using namespace std;

/* 
任务队列allTask中有若干任务Thread_Task，每个Thread_Task包含回调函数HTask_Func和参数HTASK_Param，
空闲的线程获取一个任务，并且调用HTask_Func（HTASK_Param）
*/  


//  1任务的回调函数的参数 
class HTASK_Param  
{     
    public:
        unique_ptr<int>  cfd; /*客户端fd*/   
        unique_ptr<char[]>  buf2; /*缓冲区*/   

        HTASK_Param(int& fd){ 
            cfd = make_unique<int>(fd);
        }
        HTASK_Param( HTASK_Param&& t ){ 
            cfd = move(t.cfd);
        } 
    private:
        HTASK_Param( ){}
};  

// 2任务的回调函数，也是 线程处理函数，do_work
typedef std::function< void* (unique_ptr<HTASK_Param>&  ) > HTask_Func;

// 3 任务 类型
struct Thread_Task  
{   
    HTask_Func process;    /*回调函数，任务运行时会调用此函数，也是 线程处理函数 */  
    unique_ptr<HTASK_Param>  param; /*回调函数的参数*/  
    Thread_Task(const HTask_Func a,  unique_ptr<HTASK_Param>& b ){
        process = a;
        param = move(b);
    }
} ;  
 

/*线程池类 */  
template<class HTASK, class HTASK_FUNC, class HTASK_PARAM>
class Thread_pool
{    
public: 
    std::mutex queue_lock;   // 队列锁
    std::condition_variable queue_cond;   // 队列阻塞通知,条件变量

    /* 线程池中所有等待任务, 一个任务是一个 HTASK 指针， 包含函数指针和数据 */  
    queue< unique_ptr<HTASK>  > allTask;

    /*是否销毁线程池*/  
    bool shutdown;   
    /*线程池中允许的活动线程数目*/  
    int fixed_thread_num;    

    Thread_pool (int fixed_thread_num) 
    {       
        this->fixed_thread_num = fixed_thread_num;   
        this->shutdown = false;  

        // 线程池中的线程   
        for (int i = 0; i < fixed_thread_num; ++i)  
        {      
            thread oneThread(thread_routine, this);
            oneThread.detach();
        }  
        
    }  
    ~Thread_pool ()  
    {  
        if (this->shutdown)  
            return  ;  /*防止两次调用*/  
        this->shutdown = true;  

        /*唤醒所有等待线程，线程池要销毁了*/  
        this->queue_cond.notify_all();  

        /*阻塞等待线程退出，否则就成僵尸了*/    
        std::unique_lock<std::mutex> lk(queue_lock);
        notify_all_at_thread_exit(this->queue_cond, move(lk) ); 

    }  

    //   添加任务
    int  pool_add_work (HTASK_FUNC process,  unique_ptr<HTASK_PARAM>& param)  
    {    
        /*构造一个新任务*/   
        unique_ptr<HTASK> the_task = make_unique<HTASK>(process, param);  
        { /*将任务加入到等待队列中*/   
            lock_guard<std::mutex> lk(queue_lock);  // 加锁  
            allTask.push( move(the_task) );   
        }

        /* 等待队列中有任务了，唤醒一个等待线程 */  
        queue_cond.notify_one();
        // cout << "pool_add_work succ" << endl;
        return 0;  
    }   

    
    //  线程主体: 每个线程的空转函数，也就是 在临界区队列中取出一个任务，然后执行
    static void * thread_routine (void *pool_arg)  
    {   
        // 智能指针 每个线程一个buf2
        auto buf2 = make_unique<char[]>(MAXBODY); 
        Thread_pool *pool = (Thread_pool*) pool_arg;
        printf ("starting thread 0x%ld\n", pthread_self ());  
        
        while (1)  
        {  
            unique_ptr<HTASK>  task;
            {
                /*这个操作是阻塞调用的， 并会进入阻塞状态， 
                直到拿到锁之后才会返回。  */  
                std::unique_lock<std::mutex> ulock(pool->queue_lock);  
                while ( pool->allTask.empty()  && !pool->shutdown)  
                {  
                    pool->queue_cond.wait( ulock ); // 条件变量
                    cout << "当前任务数量："<<pool->allTask.size() << endl;
                }  

                /*广播：线程池要销毁了*/  
                if (pool->shutdown)  
                {  
                    /*遇到break,continue,return等跳转语句，千万不要忘记先解锁*/   
                    cout << "thread close, id=" <<  this_thread::get_id() << endl;  
                    return (void*)0;
                }   
                /* 取出任务*/   
                task = move(pool->allTask.front());
                pool->allTask.pop();  
            } 
            /*调用回调函数，执行任务*/  
            if( task ){ 
                unique_ptr<HTASK_PARAM> param = move(task->param);
                param->buf2 = move(buf2);   // 转出
                task->process(  param  );     
                buf2  = move(param->buf2); // 转回
            } 
            else{
                cout << "error!! task is nullptr!" << endl;
            }
        }   
        cout << "一个线程被退出了: " << this_thread::get_id() << endl;
        return (void*)0;
    }   
} ;   
 

#endif

